home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / bash / bash_108 / bash-108.zoo / bash-1.08 / unwind_prot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-05  |  5.0 KB  |  216 lines

  1. /* I can't stand it anymore!  Please can't we just write the
  2.    whole Unix system in lisp or something? */
  3.  
  4. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  5.  
  6. This file is part of GNU Bash, the Bourne Again SHell.
  7.  
  8. Bash is free software; you can redistribute it and/or modify it under
  9. the terms of the GNU General Public License as published by the Free
  10. Software Foundation; either version 1, or (at your option) any later
  11. version.
  12.  
  13. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  14. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License along
  19. with Bash; see the file COPYING.  If not, write to the Free Software
  20. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  21.  
  22. /* **************************************************************** */
  23. /*                                    */
  24. /*              Unwind Protection Scheme for Bash            */
  25. /*                                    */
  26. /* **************************************************************** */
  27. #include <signal.h>
  28. #include "config.h"
  29. #include "general.h"
  30.  
  31. /* If CLEANUP is null, then ARG contains a tag to throw back to. */
  32. typedef struct _uwp {
  33.   struct _uwp *next;
  34.   Function *cleanup;
  35.   char *arg;
  36. } UNWIND_ELT;
  37.  
  38. static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
  39.  
  40. /* Run a function without interrupts. */
  41. without_interrupts (function, arg1, arg2)
  42.      Function *function;
  43.      char *arg1, *arg2;
  44. {
  45. #if defined (_POSIX_VERSION)
  46.   sigset_t set, oset;
  47.  
  48.   sigemptyset (&set);
  49.   sigaddset (&set, SIGINT);
  50.   sigprocmask (SIG_BLOCK, &set, &oset);
  51. #else
  52. #  if defined (USG)
  53.   SigHandler *old_int;
  54.  
  55.   old_int = (SigHandler *)signal (SIGINT, SIG_IGN);
  56. #  else
  57.   int oldmask = sigblock (SIGINT);
  58. #  endif
  59. #endif
  60.  
  61.   (*function)(arg1, arg2);
  62.  
  63. #if defined (_POSIX_VERSION)
  64.   sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  65. #else
  66. #  if defined (USG)
  67.   signal (SIGINT, old_int);
  68. #  else
  69.   sigsetmask (oldmask);
  70. #  endif
  71. #endif
  72. }
  73.  
  74. /* Start the beginning of a region. */
  75. begin_unwind_frame (tag)
  76.      char *tag;
  77. {
  78.   add_unwind_protect ((Function *)NULL, tag);
  79. }
  80.  
  81. /* Discard the unwind protects back to TAG. */
  82. discard_unwind_frame (tag)
  83.      char *tag;
  84. {
  85.   int unwind_frame_discard_internal ();
  86.  
  87.   without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
  88. }
  89.  
  90. /* Run the unwind protects back to TAG. */
  91. run_unwind_frame (tag)
  92.      char *tag;
  93. {
  94.   int unwind_frame_run_internal ();
  95.   without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
  96. }
  97.  
  98. /* Add the function CLEANUP with ARG to the list of unwindable things. */
  99. add_unwind_protect (cleanup, arg)
  100.      Function *cleanup;
  101.      char *arg;
  102. {
  103.   int add_unwind_protect_internal ();
  104.   without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
  105. }
  106.  
  107. /* Remove the top unwind protect from the list. */
  108. remove_unwind_protect ()
  109. {
  110.   int remove_unwind_protect_internal ();
  111.   without_interrupts (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
  112. }
  113.  
  114. /* Run the list of cleanup functions in unwind_protect_list. */
  115. run_unwind_protects ()
  116. {
  117.   int run_unwind_protects_internal ();
  118.   without_interrupts (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
  119. }
  120.  
  121. /* **************************************************************** */
  122. /*                                    */
  123. /*                        The Actual Functions                         */
  124. /*                                    */
  125. /* **************************************************************** */
  126.  
  127. add_unwind_protect_internal (cleanup, arg)
  128.      Function *cleanup;
  129.      char *arg;
  130. {
  131.   UNWIND_ELT *elt;
  132.  
  133.   elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
  134.   elt->cleanup = cleanup;
  135.   elt->arg = arg;
  136.   elt->next = unwind_protect_list;
  137.   unwind_protect_list = elt;
  138. }
  139.  
  140. remove_unwind_protect_internal ()
  141. {
  142.   UNWIND_ELT *elt = unwind_protect_list;
  143.  
  144.   if (elt)
  145.     {
  146.       unwind_protect_list = unwind_protect_list->next;
  147.       free (elt);
  148.     }
  149. }
  150.  
  151. run_unwind_protects_internal ()
  152. {
  153.   UNWIND_ELT *t, *elt = unwind_protect_list;
  154.  
  155.   while (elt)
  156.    {
  157.       /* This function can be run at strange times, like when unwinding
  158.     the entire world of unwind protects.  Thus, we may come across
  159.      an element which is simply a label for a catch frame.  Don't call
  160.      the non-existant function. */
  161.       if (elt->cleanup)
  162.     (*(elt->cleanup)) (elt->arg);
  163.  
  164.       t = elt;
  165.       elt = elt->next;
  166.       free (t);
  167.     }
  168.   unwind_protect_list = elt;
  169. }
  170.  
  171. unwind_frame_discard_internal (tag)
  172.      char *tag;
  173. {
  174.   UNWIND_ELT *elt;
  175.  
  176.   while (elt = unwind_protect_list)
  177.     {
  178.       unwind_protect_list = unwind_protect_list->next;
  179.       if (!elt->cleanup && (STREQ (elt->arg, tag)))
  180.     {
  181.       free (elt);
  182.       break;
  183.     }
  184.       else
  185.     free (elt);
  186.     }
  187. }
  188.  
  189. unwind_frame_run_internal (tag)
  190.      char *tag;
  191. {
  192.   UNWIND_ELT *elt;
  193.  
  194.   while (elt = unwind_protect_list)
  195.     {
  196.       unwind_protect_list = elt->next;
  197.  
  198.       /* If tag, then compare. */
  199.       if (!elt->cleanup)
  200.     {
  201.       if (strcmp (elt->arg, tag) == 0)
  202.         {
  203.           free (elt);
  204.           break;
  205.         }
  206.       free (elt);
  207.       continue;
  208.     }
  209.       else
  210.     {
  211.       (*(elt->cleanup)) (elt->arg);
  212.       free (elt);
  213.     }
  214.     }
  215. }
  216.